/*
 * Copyright (c)  2020,  DataPipeline
 * All rights reserved.
 *
 * Id:SQLManager.java   2020-07-16 00:18 wanglijun
 */
package cn.datacare.orm.manager.impl;

import cn.datacare.orm.connection.ConnectionSource;
import cn.datacare.orm.connection.ConnectionSourceHelper;
import cn.datacare.orm.constant.SqlSourceType;
import cn.datacare.orm.conversion.DefaultNameConversion;
import cn.datacare.orm.conversion.NameConversion;
import cn.datacare.orm.dialect.Dialect;
import cn.datacare.orm.engine.Beetl;
import cn.datacare.orm.interceptor.Interceptor;
import cn.datacare.orm.loader.ClassPathLoader;
import cn.datacare.orm.loader.SQLLoader;
import cn.datacare.orm.manager.Manager;
import cn.datacare.orm.mapper.DefaultMapperBuilder;
import cn.datacare.orm.mapper.MapperBuilder;
import cn.datacare.orm.mapping.BeanProcessor;
import cn.datacare.orm.query.*;
import cn.datacare.orm.source.*;
import cn.datacare.orm.util.kit.StringKit;
import org.beetl.core.Context;

import java.util.*;

import static cn.datacare.orm.constant.SqlSourceType.SELECT_ALL;
import static cn.datacare.orm.util.Separator.DOT;

/**
 * <p>
 * Title: SQLManager
 * </p>
 * <p>
 * Description: SQLManager
 * </p>
 * <p>
 * Copyright: Copyright (c) 2020
 * </p>
 * <p>
 * Company/Department: DataPipeline
 * </p>
 *
 * @author wanglijun
 * @version 1.0
 * @since 2020-07-16 00:18
 */
public class SQLManager extends AbstractCurdSqlManager implements Manager {
    /***
     *  每个sqlManager都有一个标示，可以通过标识来找到对应的sqlManager，用于序列化和反序列化
     */
    protected static Map<String, SQLManager> sqlManagerMap = new HashMap<>();

    private MapperBuilder mapperBuilder = new DefaultMapperBuilder(this);

    public SQLManager(Dialect dialect, ConnectionSource ds) {
        this(dialect,new ClassPathLoader(DEFAULT_SQL_PATH),ds);
    }

    public SQLManager(Dialect dialect, SQLLoader sqlLoader, ConnectionSource ds) {
        this(dialect,sqlLoader,ds,new DefaultNameConversion(),new Interceptor[]{},null);
    }

    /**
     * @param dialect
     * @param sqlLoader
     * @param ds
     * @param nc
     * @param inters
     * @param defaultSchema 数据库访问的schema，为null自动判断
     */
    public SQLManager(Dialect dialect, SQLLoader sqlLoader, ConnectionSource ds, NameConversion nc,
                      Interceptor[] inters, String defaultSchema) {
        this(dialect, sqlLoader, ds, nc, inters, defaultSchema, new Properties());
    }


    public SQLManager(Dialect dialect, SQLLoader sqlLoader, ConnectionSource ds, NameConversion nc,
                      Interceptor[] inters, String defaultSchema, Properties properties) {
        this(dialect, sqlLoader, ds, nc, inters, defaultSchema, properties, dialect.getName());
    }

    public SQLManager(Dialect dialect, SQLLoader sqlLoader, ConnectionSource connectionSource, NameConversion nameConversion,Interceptor[] inters,  String defaultSchema, Properties properties, String name) {
        this.defaultSchema = defaultSchema;
        this.inters = inters;
        this.dialect = dialect;
        this.sqlLoader = sqlLoader;
        this.sqlLoader.setDialect(this.dialect);
        this.sqlLoader.setSQLManager(this);
        this.connectionSource = connectionSource;
        this.nameConversion = nameConversion;
        this.dialect.setNameConversion(this.nameConversion);


        this.defaultSchema = defaultSchema;

        this.beetl = Beetl.builder()
                .properties(properties)
                .sqlLoader(sqlLoader)
                .build();
        //初始化
        this.dialect.setMetaDataManager(this.initMMetaDataManager(this));
        this.dialect.init(this.beetl);
        this.offsetStartZero = beetl.getOffsetStartZero();
        this.defaultBeanProcessors = new BeanProcessor(this);
        // 目前假定每个sql都有自己的名字，目前
        this.sqlManagerName = name;
        //设置集合
        sqlManagerMap.put(name, this);

    }
    @Override
    public void setMapperBuilder(MapperBuilder mapperBuilder) {
        this.mapperBuilder = mapperBuilder;
    }




    /**
     * 通过mapper接口生成dao代理
     *
     * @param mapperInterface
     * @return
     */
    public <T> T getMapper(Class<T> mapperInterface) {
        return this.mapperBuilder.getMapper(mapperInterface);
    }


    /**
     * 使用这个创建更加的简洁, 并且用户不需要理解更多的 构造函数
     *
     * @param ds 数据源
     * @return SQLManager构建器
     */
    public static SQLManagerBuilder newBuilder(ConnectionSource ds) {
        return new SQLManagerBuilder(ds);
    }

    /**
     * 快速上手的简洁构建器
     *
     * @param driver   驱动
     * @param url      url
     * @param userName userName
     * @param password password
     * @return SQLManager构建器
     */
    public static SQLManagerBuilder newBuilder(String driver, String url, String userName, String password) {
        ConnectionSource source = ConnectionSourceHelper.getSimple(driver, url, userName, password);
        return newBuilder(source);
    }


    /**
     * 每个sqlManager都有个名称，如果未指定，默认是dbStyle 返回的名称，即数据库名
     *
     * @param name
     * @return
     */
    public static SQLManager getSQLManagerByName(String name) {
        SQLManager sqlManager = sqlManagerMap.get(name);
        if (sqlManager == null) {
            throw new NullPointerException("不能根据" + name + "获得sqlManager");
        }
        return sqlManager;
    }

    /**
     *
     * @param clazz
     * @param <T>
     * @return
     */
    public <T extends StringQuery> QueryImpl<T> query(Class<T> clazz) {
        return new QueryImpl<T>(this, clazz);
    }

    /***
     * 获取Dialect 获取
     * @return Dialect
     */
    @Override
    public Dialect getDialectType() {
        return this.dialect;
    }




    public ConnectionSource getDs() {
        return this.connectionSource;
    }

    /**
     *
     * @param sqlId
     * @param resultType
     * @param query
     */
    @Override
    public void pageQuery(String sqlId, Class resultType, PageQuery query) {
    }





















    /***
     *
     * @param id
     * @return
     */
    @Override
    public SQLScript getPageSqlScript(String id) {
        return null;
    }

    /**
     * 获取数据
     *
     * @param entityClass
     * @return Object
     */
    @Override
    public Object allCount(Class entityClass) {
        return null;
    }


    /**
     * 更新消息
     *
     * @param arg
     * @return int
     */
    @Override
    public int upsertByTemplate(Object arg) {
        return 0;
    }

    /**
     * @param arg
     * @return
     */
    @Override
    public int upsert(Object arg) {
        return 0;
    }



    /**
     * btsql自动生成查询语句，查询clazz代表的表的所有数据。
     *
     * @param clazz
     * @return
     */
    public <T> List<T> all(Class<T> clazz) {
        SQLScript script = getScript(clazz, SELECT_ALL);
        return script.select(clazz, null);
    }

    /**
     * 得到增删改查模板
     *
     * @param clazz          Class
     * @param sqlSourceType SqlSourceType
     * @return SQLScript
     */
    @Override
    public SQLScript getScript(Class<?> clazz, SqlSourceType sqlSourceType) {
        //slqId 保持与DefaultSQLIdNameConversion同样命名风格
        String className = StringKit.unCapitalize(clazz.getSimpleName());
        String id = className + DOT + sqlSourceType.getClassSql();

        SQLSource tempSource = this.sqlLoader.getSQL(id);
        if (tempSource != null) {
            return new SQLScript(tempSource, this);
        }
        tempSource=this.dialect.getSqlSource(sqlSourceType,clazz);
        tempSource.setId(id);
        sqlLoader.addSQL(id, tempSource);
        return new SQLScript(tempSource, this);
    }

    /**
     * btsql自动生成查询语句，查询clazz代表的表的所有数据。
     *
     * @param clazz
     * @param start
     * @param size
     * @return
     */
    public <T> List<T> all(Class<T> clazz, long start, long size) {
        SQLScript script =this.getScript(clazz, SELECT_ALL);
        return script.select(null, clazz, null, start, size);
    }



    /**
     * 指更新
     *
     * @param batch
     * @return int[] 影响行数
     */
    @Override
    public int[] executeBatchUpdate(SQLBatchReady batch) {
        return new int[0];
    }

    /**
     * @param onConnection
     * @return
     */
    @Override
    public <T> T executeOnConnection(OnConnection<T> onConnection) {
        return null;
    }



    /***
     *
     * @param sqlId
     * @param map
     * @param resultType
     * @return
     */
    @Override
    public Object selectSingle(String sqlId, Map map, Class resultType) {
        return null;
    }

    /**
     * @param sqlId
     * @param returnType
     * @param map
     * @param offset
     * @param size
     * @return
     */
    @Override
    public Object select(String sqlId, Class returnType, Map map, long offset, long size) {
        return null;
    }




    @Override
    public Object getAssignIdByIdAutoGen(String algorithm, String param, String name) {
        return null;
    }

    /***
     *  SQLScript
     * @param sqlId
     * @return SQLScript
     */
    @Override
    public SQLScript getScript(String sqlId) {
        return null;
    }

    /***
     *
     * @param targetEntity
     * @param key
     * @return
     */
    @Override
    public boolean exist(Class targetEntity, Object key) {
        return false;
    }

    /***
     * 更新指定表
     * @param clazz Class
     * @param param 参数
     * @return 更新行数
     */
    @Override
    public int updateAll(Class<?> clazz, Object param) {
        return 0;
    }

    /***
     * ClassLoader
     * @return ClassLoader
     */
    @Override
    public ClassLoader getEntityLoader() {
        return this.getEntityLoader();
    }

    /**
     * 获取 LambdaQuery
     * @param clazz
     * @param <T>
     * @return  LambdaQuery<T>
     */
    public   <T extends StringQuery> LambdaQuery<T> lambdaQuery(Class<?> clazz) {
        return  LambdaQueryImpl.builder().clazz(clazz).sqlManager(this).build();
    }
    /**
     * 获取SQLResult
     *
     * @param s
     * @param inputParas
     * @param ctx
     * @return
     */
    @Override
    public SQLResult getSQLResult(String s, Map inputParas, Context ctx) {
        return null;
    }

    /**
     * 得到MapperBuilder,默认是DefaultMapperBuilder
     *
     * @return
     */
    public MapperBuilder getMapperBuilder() {
        return mapperBuilder;
    }




    public SQLResult getSQLResult(SQLSource source, Map params) {
        return null;
    }

    public SQLResult getSQLResult(String id, Map<String, Object> params) {
        SQLScript script =this.getScript(id);
        return script.run(params);
    }
}
